//----------------------------------------------------------
    // 日志消息格式化模块
        // 日志以什么样的格式进行输出——————对于pattern字符串的解析
//----------------------------------------------------------

#ifndef __LOG_FORMATER__
#define __LOG_FORMATER__

#include "loglevel.hpp"
#include "logmes.hpp"
#include <cassert>
#include <iostream>
#include <memory>
#include <sstream>
#include <time.h>
#include <vector>

// 日志格式化模块
namespace ymbxlog
{
    class FormatItem
    {
    public:
        using ptr = std::shared_ptr<FormatItem>;
        FormatItem() {}
        virtual ~FormatItem() {}
        virtual void Format(std::ostream &os, const LogMes &logmes) = 0;
    };
    //     size_t line,
    //     time_t time,
    //     std::thread::id tid,
    //     std::string loggername,
    //     std::string file,
    //     std::string func,
    //     std::string logmes,
    //     LogLevel::Level lev
    class LineFmtItem : public FormatItem
    {
    public:
        LineFmtItem(const std::string &str) {}
        virtual void Format(std::ostream &os, const LogMes &logmes) override
        {
            os << logmes._line;
        }
    };
    class TimeFmtItem : public FormatItem
    {
    public:
        TimeFmtItem(const std::string &tm_fmt = "%Y-%m-%d %H:%M:%S") : _tm_fmt(tm_fmt) {}
        virtual void Format(std::ostream &os, const LogMes &logmes) override
        {
            struct tm lt;
            localtime_r(&logmes._time, &lt);
            char tmp[32];
            strftime(tmp, sizeof(tmp), _tm_fmt.c_str(), &lt);
            os << tmp;
        }
    private:
        std::string _tm_fmt;
    };
    class TidFmtItem : public FormatItem
    {
    public:
        TidFmtItem(const std::string &str) {}
        virtual void Format(std::ostream &os, const LogMes &logmes) override
        {
            os << logmes._tid;
        }
    };
    class LoggernameFmtItem : public FormatItem
    {
    public:
        LoggernameFmtItem(const std::string &str) {}
        virtual void Format(std::ostream &os, const LogMes &logmes) override
        {
            os << logmes._loggername;
        }
    };
    class FileFmtItem : public FormatItem
    {
    public:
        FileFmtItem(const std::string &str) {}
        virtual void Format(std::ostream &os, const LogMes &logmes) override
        {
            os << logmes._file;
        }
    };
    class FuncFmtItem : public FormatItem
    {
    public:
        FuncFmtItem(const std::string &str) {}
        virtual void Format(std::ostream &os, const LogMes &logmes) override
        {
            os << logmes._func;
        }
    };
    class LogmesFmtItem : public FormatItem
    {
    public:
        LogmesFmtItem(const std::string &str) {}
        virtual void Format(std::ostream &os, const LogMes &logmes) override
        {
            os << logmes._logmes;
        }
    };
    class LevFmtItem : public FormatItem
    {
    public:
        LevFmtItem(const std::string &str) {}
        virtual void Format(std::ostream &os, const LogMes &logmes) override
        {
            os << LogLevel::toString(logmes._lev);
        }
    };
    class TabFmtItem : public FormatItem
    {
    public:
        TabFmtItem(const std::string &str) {}
        virtual void Format(std::ostream &os, const LogMes &logmes) override
        {
            os << "\t";
        }
    };
    class NlineFmtItem : public FormatItem
    {
    public:
        NlineFmtItem(const std::string &str) {}
        virtual void Format(std::ostream &os, const LogMes &logmes) override
        {
            os << "\n";
        }
    };
    class OtherFmtItem : public FormatItem
    {
    public:
        OtherFmtItem(std::string str) : _str(str) {}
        virtual void Format(std::ostream &os, const LogMes &logmes) override
        {
            os << _str;
        }

    private:
        std::string _str;
    };
    /*
        %p 日志等级
        %H 小时
        %M 分钟
        %S 秒
        %f 文件名
        %F 函数名
        %l 行号
        %T 制表位
        %i 日志信息
        %n 换行
        %D 日期
        %c 日志器名称
        %t 线程id
        %Y 年
        %m 月
        %d 日
    */
    class Formatter{
        public:
            using ptr=std::shared_ptr<Formatter>;
            Formatter(const std::string& pattern="%f:%l(%F)%T[%c][%t]%T%i%T[%D{%Y-%m-%d %H:%M:%S}]%n"):_pattern(pattern){
                if(!ParsePattern()){
                    Message();
                    abort();
                }

            }
            std::ostream& Format(std::ostream& os,const LogMes& logmes){
                for(auto& e:_items){
                    e->Format(os,logmes);
                }
                return os;
            }
            std::string Format(const LogMes& logmes){
                std::stringstream ss;
                Format(ss,logmes);
                return ss.str();
            }
            bool ParsePattern(){
                int i=0;
                std::string key,val;
                std::vector<std::pair<std::string,std::string>> arr;
                while(i<_pattern.size()){
                    if(_pattern[i]!='%'){
                        val.push_back(_pattern[i++]);
                        continue;
                    }
                    if(_pattern[i]=='%' && (i+1<_pattern.size() && _pattern[i+1]=='%')){
                        val.push_back('%');
                        i+=2;
                        continue;
                    }
                    if(i+1==_pattern.size()){
                        std::cout<<"%后无内容，不符合规范"<<std::endl;
                        return false;
                    }
                    arr.push_back(std::make_pair("",val));
                    val.clear();
                    key.push_back(_pattern[++i]);
                    if(i+1<_pattern.size() && _pattern[i+1]=='{'){
                        i+=2;
                        while(i<_pattern.size() && _pattern[i]!='}'){
                            val.push_back(_pattern[i++]);
                        }
                        if(i==_pattern.size()){
                            std::cout<<"缺少}，不符合规范"<<std::endl;
                            return false;
                        }
                    }
                    arr.push_back(std::make_pair(key,val));
                    key.clear();
                    val.clear();
                    i++;
                }
                for(auto& e:arr){
                    _items.push_back(CreateItem(e.first,e.second));
                }
                return true;
            }
        private:
            FormatItem::ptr CreateItem(const std::string& key,const std::string& val){
                switch(key[0]){
                    case 'p':
                        return FormatItem::ptr(new LevFmtItem(val));
                        break;
                    case 'f':
                        return FormatItem::ptr(new FileFmtItem(val));
                        break;
                    case 'F':
                        return FormatItem::ptr(new FuncFmtItem(val));
                        break;
                    case 'l':
                        return FormatItem::ptr(new LineFmtItem(val));
                        break;
                    case 'T':
                        return FormatItem::ptr(new TabFmtItem(val));
                        break;
                    case 'i':
                        return FormatItem::ptr(new LogmesFmtItem(val));
                        break;
                    case 'n':
                        return FormatItem::ptr(new NlineFmtItem(val));
                        break;
                    case 'c':
                        return FormatItem::ptr(new LoggernameFmtItem(val));
                        break;
                    case 't':
                        return FormatItem::ptr(new TidFmtItem(val));
                        break;
                    case 'D':
                        return FormatItem::ptr(new TimeFmtItem(val));
                        break;
                    default:
                        return FormatItem::ptr(new OtherFmtItem(val));
                        break;
                }
            }
            void Message(){
                std::cout<<"请输入正确的格式：\n\
                            示例：\n\
                                %f:%l(%F)%T[%c][%t]%T%m%T[%D{%Y-%m-%d %H:%M:%S}]%n\n\
                            内容:\n\
                                %p 日志等级\n\
                                %H 小时\n\
                                %M 分钟\n\
                                %S 秒\n\
                                %f 文件名\n\
                                %F 函数名\n\
                                %l 行号\n\
                                %T 制表位\n\
                                %m 日志信息\n\
                                %n 换行\n\
                                %d 日期\n\
                                %c 日志器名称\n\
                                %t 线程id\n\
                                %Y 年\n\
                                %m 月\n\
                                %d 日\n";
            }
        private:
            std::string _pattern;
            std::vector<FormatItem::ptr> _items;
    };
}

#endif